package com.t2two.example.common.utils;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;

import java.math.BigInteger;
import java.security.Security;
import java.security.SecureRandom;

/**
 * @version 1.0
 * @description: TODO
 * @author: lifei
 * @date: 2025/2/17 10:17
 */
public class SM2Util1 {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    private static final X9ECParameters EC_PARAMS = GMNamedCurves.getByName("sm2p256v1");
    private static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(
            EC_PARAMS.getCurve(),
            EC_PARAMS.getG(),
            EC_PARAMS.getN(),
            EC_PARAMS.getH()
    );

    /**
     * SM2加密
     * @param publicKeyHex 公钥Hex字符串（04开头）
     * @param data 明文数据
     * @return 密文Hex字符串
     */
    public static String encrypt(String publicKeyHex, byte[] data) {
        try {
            ECPoint publicKeyPoint = EC_PARAMS.getCurve().decodePoint(Hex.decode(publicKeyHex));
            ECPublicKeyParameters publicKeyParams = new ECPublicKeyParameters(publicKeyPoint, DOMAIN_PARAMS);

            SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
            engine.init(true, new ParametersWithRandom(publicKeyParams, new SecureRandom()));

            byte[] encrypted = engine.processBlock(data, 0, data.length);
            return Hex.toHexString(encrypted);
        } catch (Exception e) {
            throw new RuntimeException("SM2加密失败", e);
        }
    }

    /**
     * SM2解密
     * @param privateKeyHex 私钥Hex字符串（64字符）
     * @param cipherTextHex 密文Hex字符串
     * @return 解密后的明文
     */
    public static byte[] decrypt(String privateKeyHex, String cipherTextHex) {
        try {
            BigInteger privateKey = new BigInteger(privateKeyHex, 16);
            ECPrivateKeyParameters privateKeyParams = new ECPrivateKeyParameters(privateKey, DOMAIN_PARAMS);

            SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
            engine.init(false, privateKeyParams);

            byte[] cipherBytes = Hex.decode(cipherTextHex);
            return engine.processBlock(cipherBytes, 0, cipherBytes.length);
        } catch (Exception e) {
            throw new RuntimeException("SM2解密失败", e);
        }
    }

    /**
     * 双重解密
     * @param firstPrivateKey  第一次解密私钥
     * @param secondPrivateKey 第二次解密私钥
     * @param cipherText       密文
     * @return 最终明文
     */
    public static String doubleDecrypt(String firstPrivateKey,
                                       String secondPrivateKey,
                                       String cipherText) {
        // 第一次解密
        byte[] firstDecrypted = decrypt(firstPrivateKey, cipherText);
        // 第二次解密
        byte[] secondDecrypted = decrypt(secondPrivateKey, Hex.toHexString(firstDecrypted));

        return new String(secondDecrypted);
    }

    public static void main(String[] args) {
        // 示例用法
        String publicKey = "042fe5c8884b8abe9016b12e34af58095ec58cd4313732168e39d258f3197bf96a2e7ffb84676cfd53a964bbae5d28d5130c77100cbbea6d383def8c3c1a823993"; // 替换为实际公钥
        String privateKey1 = "e0e6b3c1cd7e76db5f9b733bc1b1720db81029129b0ccaf1228d8297092d715d";
        String privateKey2 = "3c57e96dac2d6d0dfd92e400ebb609e584b148b755968d898bd25f2";

        // 加密测试
        String originalData = "需要加密的数据";
        String encryptedData = encrypt(publicKey, originalData.getBytes());
        System.out.println("加密结果：" + encryptedData);

        String str = new String(decrypt(privateKey1, encryptedData));
        System.out.println("11111111111111 "+str);
        // 双重解密测试
        String decryptedData = doubleDecrypt(privateKey1, privateKey2, encryptedData);
        System.out.println("解密结果：" + decryptedData);
    }
}
